package org.sfx.rich

import javafx.beans.value.WritableValue
import javafx.beans.value.ChangeListener
import javafx.beans.value.ObservableValue
import javafx.collections.ListChangeListener
import javafx.collections.ObservableList
import javafx.event.ActionEvent
import javafx.event.EventHandler
import javafx.scene.Node
import java.lang.reflect.Member
import java.lang.reflect.Method
import java.lang.reflect.Field
import javafx.scene.shape.Rectangle
import javafx.scene.Scene
import javafx.stage.Window
import org.sfx.util.Capabilities._
import java.lang.reflect.Member
import java.lang.reflect.AccessibleObject
import java.lang.reflect.AnnotatedElement
import java.lang.reflect.Constructor
import java.lang.reflect.GenericArrayType
import java.lang.reflect.GenericDeclaration
import java.lang.reflect.ParameterizedType
import java.lang.reflect.WildcardType
import java.lang.reflect.Type
import java.lang.reflect.TypeVariable
import javafx.application.Platform

object Enrich {
  def safeNull[T](result: => T): Option[T] = try {
    Some(result)
  } catch {
    case e: NullPointerException => None
  }
  
  def runLater(f: => Unit): Unit = {
    Platform.runLater(new Runnable() { def run(): Unit = f })
  }
  
  implicit def enrichAccessibleObject(underlying: AccessibleObject) = RichAccessibleObject(underlying)
  implicit def enrichAnnotatedElement(underlying: AnnotatedElement) = RichAnnotatedElement(underlying)
  implicit def enrichClass[T](underlying: Class[T]) = RichClass[T](underlying)
  implicit def enrichConstructor[T](underlying: Constructor[T]) = RichConstructor[T](underlying)
  implicit def enrichField(underlying: Field) = RichField(underlying)
  implicit def enrichJavaCollection[T](delegate: java.util.Collection[T]) = RichJavaCollection[T](delegate)
  implicit def enrichJavaList[T](delegate: java.util.List[T]) = new RichJavaList[T](delegate)
  implicit def enrichGenericArrayType(underlying: GenericArrayType) = RichGenericArrayType(underlying)
  implicit def enrichGenericDeclaration(underlying: GenericDeclaration) = RichGenericDeclaration(underlying)
  implicit def enrichListChangeListenerChange[E](underlying: ListChangeListener.Change[E]) = new RichListChangeListenerChange(underlying)
  implicit def enrichMember(underlying: Member) = RichMember(underlying)
  implicit def enrichMethod(underlying: Method) = RichMethod(underlying)
  implicit def enrichNode[T](raw: Node) = new RichNode(raw)
  implicit def enrichObject(underlying: Object) = RichObject(underlying)
  implicit def enrichObservableList[T](raw: ObservableList[T]) = new RichObservableList[T](raw)
  implicit def enrichPackage(underlying: Package) = new RichPackage(underlying)
  implicit def enrichParameterizedType(underlying: ParameterizedType) = new RichParameterizedType(underlying)
  implicit def enrichRectangle(underlying: Rectangle) = new RichRectangle(underlying)
  implicit def enrichScene(underlying: Scene) = new RichScene(underlying)
  implicit def enrichString(underlying: String) = new RichString(underlying)
  implicit def enrichType(underlying: Type) = new RichType(underlying)
  implicit def enrichTypeVariable[T <: GenericDeclaration](underlying: TypeVariable[T]) = new RichTypeVariable[T](underlying)
  implicit def enrichWildcardType(underlying: WildcardType) = new RichWildcardType(underlying)
  implicit def enrichWritableValue[T](raw: WritableValue[T]) = new RichWritableValue[T](raw)
  implicit def enrichWindow(underlying: Window) = new RichWindow(underlying)

  type CanSetOnAction = { def setOnAction(x: EventHandler[ActionEvent])}
  implicit def enrichCanSetOnAction(ref: CanSetOnAction) = new RichRef[CanSetOnAction](ref) {
    def onAction(f: ActionEvent => Unit): Unit = new EventHandler[ActionEvent]() {
      def handle(event: ActionEvent): Unit = f(event)
    }
  }

  implicit def enrichCanAddChangeHandler[T](underlying: CanAddRemoveChangeListener[T]) = new RichCanAddRemoveChangeListener[T](underlying)
}
